Skip to main content

Open Policy Agent

Open Policy Agent, or OPA, is an open source, general purpose policy engine.It’s a project that started in 2016 aimed at unifying policy enforcement across different technologies and systems. Today, OPA is used by giant players within the tech industry OPA decouples policy decisions from other responsibilities of an application, like those commonly referred to as business logic. OPA works equally well making decisions for Kubernetes, Microservices, functional application authorization and more, thanks to its single unified policy language.

What is Policy?

A policy can be thought of as a set of rules. As such, any organization is going to have a number of policies in place, and even an organization without formal policies in place will still need to comply with regulations, agreements and laws. Simply put, policy is everywhere. In software systems, policy might describe things like:

  • What tables inside a database contain personally identifiable information (PII).
  • Which machines on a network should be considered trusted.
  • Expected salary ranges for employees based on years of experience.
  • Default resource allocation for new application deployments.
  • What roles are required to perform different actions in a system.

This last example of a policy is what we normally call authorization, and is a special type of policy that governs who gets to do what in a given system. In order to enforce authorization decisions, a process to establish the identity of the user must normally have been completed. This process is authentication, and while a distinct concept from authorization, authorization often depends on attributes retrieved in the authentication process, such as the roles a user may have, or whether multi-factor authentication (MFA) was used in the login process. This type of attributes is often referred to as claims.

Why Open Policy Agent?

  • Rego: Open Policy Agent uses a high level declarative language called Rego to describe policy. Rego makes it easy to build policy rules around hierarchical structured data, such as that represented in JSON or YAML, prevalent in almost all systems today. Having a purpose built policy language allows policy to be described succinctly using primitives
  • General-purpose: OPA can be used to express policies and rules against arbitrary structured data .Common use cases include application and microservice authorization, Kubernetes admission control, infrastructure policies and configuration management. OPA can be embedded as a library, deployed as a daemon, or simply run on the command-line.
  • Cloud-native: OPA is a graduated project within the Cloud Native Computing Foundation (CNCF) along with other prominent cloud-native projects, such as Kubernetes, Envoy and Prometheus. OPA was built from the ground up to run in containerized, cloud native environments, and its lightweight nature allows it to be deployed in highly distributed environments.
  • Open source: All OPA code is released under a liberal Apache 2 license. This allows anyone to read and modify the source code to fit their needs, for personal user or commercial applications. In fact, several companies integrate OPA in their services and products!
  • Community and ecosystem: The general-purpose model of OPA, along with its open source licensing and its many qualities as a policy engine, has resulted in a thriving community and ecosystem to grow around the project. Check out the project on GitHub. Additionally, the OPA ecosystem page lists more than 50 integrations from both corporations and individuals .
  • Centralized management: OPA’s management APIs allow for OPA to pull policy and data bundles, report health and status and send decision logs, from/to a central control plane component, such as the Styra Declarative Authorization Service (DAS). This enables control, management and monitoring of OPA even in distributed environments with hundreds or thousands of OPAs deployed.

How Does OPA Work?

Let’s say that you’re implementing the Payments service of our example application. This service is responsible for handling customer payments. It exposes an API where it accepts payment from the customer. It also allows the user to query which payments were made by a specific customer. So, to obtain an array containing the purchases done by Jane, who is one of the company’s customers, you send a GET request to the API with the path /payment/jane. You provide your credential information in the Authorization header and send the request. The response would be a JSON array with the data you requested. However, since you don’t want just anyone with network access to have access to the Payments API to see such sensitive data, you need to enforce an authorization policy. OPA addresses the issue in the following way:

  • The Payments API queries OPA for a decision. It accompanies this query with some attributes like the HTTP method used in the request, the path, the user, and so on.
  • OPA validates those attributes against data already provided to it.
  • After validation, OPA sends a decision to the requesting API with either allow or deny.

Example :

download

There are three kinds of components in the system:

  • Servers expose zero or more protocols (e.g., http, ssh, etc.).
  • Networks connect servers and can be public or private. Public networks are connected to the Internet.
  • Ports attach servers to networks.

All of the servers, networks, and ports are provisioned by a script. The script receives a JSON representation of the system as input:

{
"servers": [
{"id": "app", "protocols": ["https", "ssh"], "ports": ["p1", "p2", "p3"]},
{"id": "db", "protocols": ["mysql"], "ports": ["p3"]},
{"id": "cache", "protocols": ["memcache"], "ports": ["p3"]},
{"id": "ci", "protocols": ["http"], "ports": ["p1", "p2"]},
{"id": "busybox", "protocols": ["telnet"], "ports": ["p1"]}
],
"networks": [
{"id": "net1", "public": false},
{"id": "net2", "public": false},
{"id": "net3", "public": true},
{"id": "net4", "public": true}
],
"ports": [
{"id": "p1", "network": "net1"},
{"id": "p2", "network": "net3"},
{"id": "p3", "network": "net2"}
]
}